package com.hh.jwtdemo.interceptor;

import com.hh.jwtdemo.annotaion.EncryptedField;
import com.hh.jwtdemo.utils.FieldCryptoUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Map;

@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class,
                RowBounds.class, ResultHandler.class})
})
public class EncryptInterceptor2 implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];

        // 统一参数处理（INSERT/UPDATE/SELECT的WHERE条件）
        processParameters(ms, parameter);

        Object result = invocation.proceed();

        // 结果集解密处理
        if (SqlCommandType.SELECT == ms.getSqlCommandType() && result instanceof List) {
            for (Object obj : (List<?>) result) {
                processFields(obj, false);
            }
        }
        return result;
    }

    @SneakyThrows
    private void processParameters(MappedStatement ms, Object parameter) {
        if (parameter == null) return;

        // 处理不同参数类型
        if (parameter instanceof Map) {
            // 处理@Param多参数情况
            ((Map<?, ?>) parameter).values().forEach(this::processParameterObject);
        } else {
            // 处理单参数情况
            processParameterObject(parameter);
        }
    }


    private void processParameterObject(Object paramObj) {
        if (paramObj == null) return;

        // 处理基本类型包装类
        if (isPrimitiveOrWrapper(paramObj.getClass())) return;

        // 处理集合类型参数
        if (paramObj instanceof Collection) {
            ((Collection<?>) paramObj).forEach(this::processParameterObject);
            return;
        }

        // 递归处理对象字段
        try {
            processFields(paramObj, true);
        } catch (Exception e) {
            log.info("处理对象字段异常,{}",e);
        }
    }

    private void processFields(Object obj, boolean isEncrypt) throws Exception {
        if (obj == null) return;

        Class<?> clazz = obj.getClass();
        MetaObject metaObject = SystemMetaObject.forObject(obj);

        while (clazz != null) {
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(EncryptedField.class)) {
                    String fieldName = field.getName();
                    Object value = metaObject.getValue(fieldName);
                    if (value instanceof String) {
                        String processedValue = isEncrypt ?
                                FieldCryptoUtil.encrypt((String) value) :
                                FieldCryptoUtil.decrypt((String) value);
                        metaObject.setValue(fieldName, processedValue);
                    }
                }
            }
            clazz = clazz.getSuperclass();
        }
    }

    private boolean isPrimitiveOrWrapper(Class<?> clazz) {
        return clazz.isPrimitive() ||
                Number.class.isAssignableFrom(clazz) ||
                CharSequence.class.isAssignableFrom(clazz) ||
                Boolean.class == clazz;
    }

    // 保留原有的plugin和setProperties方法
}